1   /*
2    * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.reflect.annotation;
27  
28  import java.lang.annotation.*;
29  import java.util.*;
30  import java.nio.ByteBuffer;
31  import java.nio.BufferUnderflowException;
32  import java.lang.reflect.*;
33  import sun.reflect.ConstantPool;
34  
35  import sun.reflect.generics.parser.SignatureParser;
36  import sun.reflect.generics.tree.TypeSignature;
37  import sun.reflect.generics.factory.GenericsFactory;
38  import sun.reflect.generics.factory.CoreReflectionFactory;
39  import sun.reflect.generics.visitor.Reifier;
40  import sun.reflect.generics.scope.ClassScope;
41  
42  /**
43   * Parser for Java programming language annotations.  Translates
44   * annotation byte streams emitted by compiler into annotation objects.
45   *
46   * @author  Josh Bloch
47   * @since   1.5
48   */
49  public class AnnotationParser {
50      /**
51       * Parses the annotations described by the specified byte array.
52       * resolving constant references in the specified constant pool.
53       * The array must contain an array of annotations as described
54       * in the RuntimeVisibleAnnotations_attribute:
55       *
56       *   u2 num_annotations;
57       *   annotation annotations[num_annotations];
58       *
59       * @throws AnnotationFormatError if an annotation is found to be
60       *         malformed.
61       */
62      public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
63                  byte[] rawAnnotations,
64                  ConstantPool constPool,
65                  Class<?> container) {
66          if (rawAnnotations == null)
67              return Collections.emptyMap();
68  
69          try {
70              return parseAnnotations2(rawAnnotations, constPool, container);
71          } catch(BufferUnderflowException e) {
72              throw new AnnotationFormatError("Unexpected end of annotations.");
73          } catch(IllegalArgumentException e) {
74              // Type mismatch in constant pool
75              throw new AnnotationFormatError(e);
76          }
77      }
78  
79      private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
80                  byte[] rawAnnotations,
81                  ConstantPool constPool,
82                  Class<?> container) {
83          Map<Class<? extends Annotation>, Annotation> result =
84              new LinkedHashMap<Class<? extends Annotation>, Annotation>();
85          ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
86          int numAnnotations = buf.getShort() & 0xFFFF;
87          for (int i = 0; i < numAnnotations; i++) {
88              Annotation a = parseAnnotation(buf, constPool, container, false);
89              if (a != null) {
90                  Class<? extends Annotation> klass = a.annotationType();
91                  AnnotationType type = AnnotationType.getInstance(klass);
92                  if (type.retention() == RetentionPolicy.RUNTIME)
93                      if (result.put(klass, a) != null)
94                          throw new AnnotationFormatError(
95                              "Duplicate annotation for class: "+klass+": " + a);
96              }
97          }
98          return result;
99      }
100 
101     /**
102      * Parses the parameter annotations described by the specified byte array.
103      * resolving constant references in the specified constant pool.
104      * The array must contain an array of annotations as described
105      * in the RuntimeVisibleParameterAnnotations_attribute:
106      *
107      *    u1 num_parameters;
108      *    {
109      *        u2 num_annotations;
110      *        annotation annotations[num_annotations];
111      *    } parameter_annotations[num_parameters];
112      *
113      * Unlike parseAnnotations, rawAnnotations must not be null!
114      * A null value must be handled by the caller.  This is so because
115      * we cannot determine the number of parameters if rawAnnotations
116      * is null.  Also, the caller should check that the number
117      * of parameters indicated by the return value of this method
118      * matches the actual number of method parameters.  A mismatch
119      * indicates that an AnnotationFormatError should be thrown.
120      *
121      * @throws AnnotationFormatError if an annotation is found to be
122      *         malformed.
123      */
124     public static Annotation[][] parseParameterAnnotations(
125                     byte[] rawAnnotations,
126                     ConstantPool constPool,
127                     Class<?> container) {
128         try {
129             return parseParameterAnnotations2(rawAnnotations, constPool, container);
130         } catch(BufferUnderflowException e) {
131             throw new AnnotationFormatError(
132                 "Unexpected end of parameter annotations.");
133         } catch(IllegalArgumentException e) {
134             // Type mismatch in constant pool
135             throw new AnnotationFormatError(e);
136         }
137     }
138 
139     private static Annotation[][] parseParameterAnnotations2(
140                     byte[] rawAnnotations,
141                     ConstantPool constPool,
142                     Class<?> container) {
143         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
144         int numParameters = buf.get() & 0xFF;
145         Annotation[][] result = new Annotation[numParameters][];
146 
147         for (int i = 0; i < numParameters; i++) {
148             int numAnnotations = buf.getShort() & 0xFFFF;
149             List<Annotation> annotations =
150                 new ArrayList<Annotation>(numAnnotations);
151             for (int j = 0; j < numAnnotations; j++) {
152                 Annotation a = parseAnnotation(buf, constPool, container, false);
153                 if (a != null) {
154                     AnnotationType type = AnnotationType.getInstance(
155                                               a.annotationType());
156                     if (type.retention() == RetentionPolicy.RUNTIME)
157                         annotations.add(a);
158                 }
159             }
160             result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
161         }
162         return result;
163     }
164 
165     private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
166                     new Annotation[0];
167 
168     /**
169      * Parses the annotation at the current position in the specified
170      * byte buffer, resolving constant references in the specified constant
171      * pool.  The cursor of the byte buffer must point to an "annotation
172      * structure" as described in the RuntimeVisibleAnnotations_attribute:
173      *
174      * annotation {
175      *    u2    type_index;
176      *       u2    num_member_value_pairs;
177      *       {    u2    member_name_index;
178      *             member_value value;
179      *       }    member_value_pairs[num_member_value_pairs];
180      *    }
181      * }
182      *
183      * Returns the annotation, or null if the annotation's type cannot
184      * be found by the VM, or is not a valid annotation type.
185      *
186      * @param exceptionOnMissingAnnotationClass if true, throw
187      * TypeNotPresentException if a referenced annotation type is not
188      * available at runtime
189      */
190     private static Annotation parseAnnotation(ByteBuffer buf,
191                                               ConstantPool constPool,
192                                               Class<?> container,
193                                               boolean exceptionOnMissingAnnotationClass) {
194         int typeIndex = buf.getShort() & 0xFFFF;
195         Class<? extends Annotation> annotationClass = null;
196         String sig = "[unknown]";
197         try {
198             try {
199                 sig = constPool.getUTF8At(typeIndex);
200                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
201             } catch (IllegalArgumentException ex) {
202                 // support obsolete early jsr175 format class files
203                 annotationClass = constPool.getClassAt(typeIndex);
204             }
205         } catch (NoClassDefFoundError e) {
206             if (exceptionOnMissingAnnotationClass)
207                 // note: at this point sig is "[unknown]" or VM-style
208                 // name instead of a binary name
209                 throw new TypeNotPresentException(sig, e);
210             skipAnnotation(buf, false);
211             return null;
212         }
213         catch (TypeNotPresentException e) {
214             if (exceptionOnMissingAnnotationClass)
215                 throw e;
216             skipAnnotation(buf, false);
217             return null;
218         }
219         AnnotationType type = null;
220         try {
221             type = AnnotationType.getInstance(annotationClass);
222         } catch (IllegalArgumentException e) {
223             skipAnnotation(buf, false);
224             return null;
225         }
226 
227         Map<String, Class<?>> memberTypes = type.memberTypes();
228         Map<String, Object> memberValues =
229             new LinkedHashMap<String, Object>(type.memberDefaults());
230 
231         int numMembers = buf.getShort() & 0xFFFF;
232         for (int i = 0; i < numMembers; i++) {
233             int memberNameIndex = buf.getShort() & 0xFFFF;
234             String memberName = constPool.getUTF8At(memberNameIndex);
235             Class<?> memberType = memberTypes.get(memberName);
236 
237             if (memberType == null) {
238                 // Member is no longer present in annotation type; ignore it
239                 skipMemberValue(buf);
240             } else {
241                 Object value = parseMemberValue(memberType, buf, constPool, container);
242                 if (value instanceof AnnotationTypeMismatchExceptionProxy)
243                     ((AnnotationTypeMismatchExceptionProxy) value).
244                         setMember(type.members().get(memberName));
245                 memberValues.put(memberName, value);
246             }
247         }
248         return annotationForMap(annotationClass, memberValues);
249     }
250 
251     /**
252      * Returns an annotation of the given type backed by the given
253      * member -> value map.
254      */
255     public static Annotation annotationForMap(
256         Class<? extends Annotation> type, Map<String, Object> memberValues)
257     {
258         return (Annotation) Proxy.newProxyInstance(
259             type.getClassLoader(), new Class[] { type },
260             new AnnotationInvocationHandler(type, memberValues));
261     }
262 
263     /**
264      * Parses the annotation member value at the current position in the
265      * specified byte buffer, resolving constant references in the specified
266      * constant pool.  The cursor of the byte buffer must point to a
267      * "member_value structure" as described in the
268      * RuntimeVisibleAnnotations_attribute:
269      *
270      *  member_value {
271      *    u1 tag;
272      *    union {
273      *       u2   const_value_index;
274      *       {
275      *           u2   type_name_index;
276      *           u2   const_name_index;
277      *       } enum_const_value;
278      *       u2   class_info_index;
279      *       annotation annotation_value;
280      *       {
281      *           u2    num_values;
282      *           member_value values[num_values];
283      *       } array_value;
284      *    } value;
285      * }
286      *
287      * The member must be of the indicated type. If it is not, this
288      * method returns an AnnotationTypeMismatchExceptionProxy.
289      */
290     public static Object parseMemberValue(Class<?> memberType,
291                                           ByteBuffer buf,
292                                           ConstantPool constPool,
293                                           Class<?> container) {
294         Object result = null;
295         int tag = buf.get();
296         switch(tag) {
297           case 'e':
298               return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
299           case 'c':
300               result = parseClassValue(buf, constPool, container);
301               break;
302           case '@':
303               result = parseAnnotation(buf, constPool, container, true);
304               break;
305           case '[':
306               return parseArray(memberType, buf, constPool, container);
307           default:
308               result = parseConst(tag, buf, constPool);
309         }
310 
311         if (!(result instanceof ExceptionProxy) &&
312             !memberType.isInstance(result))
313             result = new AnnotationTypeMismatchExceptionProxy(
314                 result.getClass() + "[" + result + "]");
315         return result;
316     }
317 
318     /**
319      * Parses the primitive or String annotation member value indicated by
320      * the specified tag byte at the current position in the specified byte
321      * buffer, resolving constant reference in the specified constant pool.
322      * The cursor of the byte buffer must point to an annotation member value
323      * of the type indicated by the specified tag, as described in the
324      * RuntimeVisibleAnnotations_attribute:
325      *
326      *       u2   const_value_index;
327      */
328     private static Object parseConst(int tag,
329                                      ByteBuffer buf, ConstantPool constPool) {
330         int constIndex = buf.getShort() & 0xFFFF;
331         switch(tag) {
332           case 'B':
333             return Byte.valueOf((byte) constPool.getIntAt(constIndex));
334           case 'C':
335             return Character.valueOf((char) constPool.getIntAt(constIndex));
336           case 'D':
337             return Double.valueOf(constPool.getDoubleAt(constIndex));
338           case 'F':
339             return Float.valueOf(constPool.getFloatAt(constIndex));
340           case 'I':
341             return Integer.valueOf(constPool.getIntAt(constIndex));
342           case 'J':
343             return Long.valueOf(constPool.getLongAt(constIndex));
344           case 'S':
345             return Short.valueOf((short) constPool.getIntAt(constIndex));
346           case 'Z':
347             return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
348           case 's':
349             return constPool.getUTF8At(constIndex);
350           default:
351             throw new AnnotationFormatError(
352                 "Invalid member-value tag in annotation: " + tag);
353         }
354     }
355 
356     /**
357      * Parses the Class member value at the current position in the
358      * specified byte buffer, resolving constant references in the specified
359      * constant pool.  The cursor of the byte buffer must point to a "class
360      * info index" as described in the RuntimeVisibleAnnotations_attribute:
361      *
362      *       u2   class_info_index;
363      */
364     private static Object parseClassValue(ByteBuffer buf,
365                                           ConstantPool constPool,
366                                           Class<?> container) {
367         int classIndex = buf.getShort() & 0xFFFF;
368         try {
369             try {
370                 String sig = constPool.getUTF8At(classIndex);
371                 return parseSig(sig, container);
372             } catch (IllegalArgumentException ex) {
373                 // support obsolete early jsr175 format class files
374                 return constPool.getClassAt(classIndex);
375             }
376         } catch (NoClassDefFoundError e) {
377             return new TypeNotPresentExceptionProxy("[unknown]", e);
378         }
379         catch (TypeNotPresentException e) {
380             return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
381         }
382     }
383 
384     private static Class<?> parseSig(String sig, Class<?> container) {
385         if (sig.equals("V")) return void.class;
386         SignatureParser parser = SignatureParser.make();
387         TypeSignature typeSig = parser.parseTypeSig(sig);
388         GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
389         Reifier reify = Reifier.make(factory);
390         typeSig.accept(reify);
391         Type result = reify.getResult();
392         return toClass(result);
393     }
394     static Class<?> toClass(Type o) {
395         if (o instanceof GenericArrayType)
396             return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
397                                      0)
398                 .getClass();
399         return (Class)o;
400     }
401 
402     /**
403      * Parses the enum constant member value at the current position in the
404      * specified byte buffer, resolving constant references in the specified
405      * constant pool.  The cursor of the byte buffer must point to a
406      * "enum_const_value structure" as described in the
407      * RuntimeVisibleAnnotations_attribute:
408      *
409      *       {
410      *           u2   type_name_index;
411      *           u2   const_name_index;
412      *       } enum_const_value;
413      */
414     private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
415                                          ConstantPool constPool,
416                                          Class<?> container) {
417         int typeNameIndex = buf.getShort() & 0xFFFF;
418         String typeName  = constPool.getUTF8At(typeNameIndex);
419         int constNameIndex = buf.getShort() & 0xFFFF;
420         String constName = constPool.getUTF8At(constNameIndex);
421 
422         if (!typeName.endsWith(";")) {
423             // support now-obsolete early jsr175-format class files.
424             if (!enumType.getName().equals(typeName))
425             return new AnnotationTypeMismatchExceptionProxy(
426                 typeName + "." + constName);
427         } else if (enumType != parseSig(typeName, container)) {
428             return new AnnotationTypeMismatchExceptionProxy(
429                 typeName + "." + constName);
430         }
431 
432         try {
433             return  Enum.valueOf(enumType, constName);
434         } catch(IllegalArgumentException e) {
435             return new EnumConstantNotPresentExceptionProxy(
436                 (Class<? extends Enum>)enumType, constName);
437         }
438     }
439 
440     /**
441      * Parses the array value at the current position in the specified byte
442      * buffer, resolving constant references in the specified constant pool.
443      * The cursor of the byte buffer must point to an array value struct
444      * as specified in the RuntimeVisibleAnnotations_attribute:
445      *
446      *       {
447      *           u2    num_values;
448      *           member_value values[num_values];
449      *       } array_value;
450      *
451      * If the array values do not match arrayType, an
452      * AnnotationTypeMismatchExceptionProxy will be returned.
453      */
454     private static Object parseArray(Class<?> arrayType,
455                                      ByteBuffer buf,
456                                      ConstantPool constPool,
457                                      Class<?> container) {
458         int length = buf.getShort() & 0xFFFF;  // Number of array components
459         Class<?> componentType = arrayType.getComponentType();
460 
461         if (componentType == byte.class) {
462             return parseByteArray(length, buf, constPool);
463         } else if (componentType == char.class) {
464             return parseCharArray(length, buf, constPool);
465         } else if (componentType == double.class) {
466             return parseDoubleArray(length, buf, constPool);
467         } else if (componentType == float.class) {
468             return parseFloatArray(length, buf, constPool);
469         } else if (componentType == int.class) {
470             return parseIntArray(length, buf, constPool);
471         } else if (componentType == long.class) {
472             return parseLongArray(length, buf, constPool);
473         } else if (componentType == short.class) {
474             return parseShortArray(length, buf, constPool);
475         } else if (componentType == boolean.class) {
476             return parseBooleanArray(length, buf, constPool);
477         } else if (componentType == String.class) {
478             return parseStringArray(length, buf, constPool);
479         } else if (componentType == Class.class) {
480             return parseClassArray(length, buf, constPool, container);
481         } else if (componentType.isEnum()) {
482             return parseEnumArray(length, (Class<? extends Enum>)componentType, buf,
483                                   constPool, container);
484         } else {
485             assert componentType.isAnnotation();
486             return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
487                                         constPool, container);
488         }
489     }
490 
491     private static Object parseByteArray(int length,
492                                   ByteBuffer buf, ConstantPool constPool) {
493         byte[] result = new byte[length];
494         boolean typeMismatch = false;
495         int tag = 0;
496 
497         for (int i = 0; i < length; i++) {
498             tag = buf.get();
499             if (tag == 'B') {
500                 int index = buf.getShort() & 0xFFFF;
501                 result[i] = (byte) constPool.getIntAt(index);
502             } else {
503                 skipMemberValue(tag, buf);
504                 typeMismatch = true;
505             }
506         }
507         return typeMismatch ? exceptionProxy(tag) : result;
508     }
509 
510     private static Object parseCharArray(int length,
511                                   ByteBuffer buf, ConstantPool constPool) {
512         char[] result = new char[length];
513         boolean typeMismatch = false;
514         byte tag = 0;
515 
516         for (int i = 0; i < length; i++) {
517             tag = buf.get();
518             if (tag == 'C') {
519                 int index = buf.getShort() & 0xFFFF;
520                 result[i] = (char) constPool.getIntAt(index);
521             } else {
522                 skipMemberValue(tag, buf);
523                 typeMismatch = true;
524             }
525         }
526         return typeMismatch ? exceptionProxy(tag) : result;
527     }
528 
529     private static Object parseDoubleArray(int length,
530                                     ByteBuffer buf, ConstantPool constPool) {
531         double[] result = new  double[length];
532         boolean typeMismatch = false;
533         int tag = 0;
534 
535         for (int i = 0; i < length; i++) {
536             tag = buf.get();
537             if (tag == 'D') {
538                 int index = buf.getShort() & 0xFFFF;
539                 result[i] = constPool.getDoubleAt(index);
540             } else {
541                 skipMemberValue(tag, buf);
542                 typeMismatch = true;
543             }
544         }
545         return typeMismatch ? exceptionProxy(tag) : result;
546     }
547 
548     private static Object parseFloatArray(int length,
549                                    ByteBuffer buf, ConstantPool constPool) {
550         float[] result = new float[length];
551         boolean typeMismatch = false;
552         int tag = 0;
553 
554         for (int i = 0; i < length; i++) {
555             tag = buf.get();
556             if (tag == 'F') {
557                 int index = buf.getShort() & 0xFFFF;
558                 result[i] = constPool.getFloatAt(index);
559             } else {
560                 skipMemberValue(tag, buf);
561                 typeMismatch = true;
562             }
563         }
564         return typeMismatch ? exceptionProxy(tag) : result;
565     }
566 
567     private static Object parseIntArray(int length,
568                                  ByteBuffer buf, ConstantPool constPool) {
569         int[] result = new  int[length];
570         boolean typeMismatch = false;
571         int tag = 0;
572 
573         for (int i = 0; i < length; i++) {
574             tag = buf.get();
575             if (tag == 'I') {
576                 int index = buf.getShort() & 0xFFFF;
577                 result[i] = constPool.getIntAt(index);
578             } else {
579                 skipMemberValue(tag, buf);
580                 typeMismatch = true;
581             }
582         }
583         return typeMismatch ? exceptionProxy(tag) : result;
584     }
585 
586     private static Object parseLongArray(int length,
587                                   ByteBuffer buf, ConstantPool constPool) {
588         long[] result = new long[length];
589         boolean typeMismatch = false;
590         int tag = 0;
591 
592         for (int i = 0; i < length; i++) {
593             tag = buf.get();
594             if (tag == 'J') {
595                 int index = buf.getShort() & 0xFFFF;
596                 result[i] = constPool.getLongAt(index);
597             } else {
598                 skipMemberValue(tag, buf);
599                 typeMismatch = true;
600             }
601         }
602         return typeMismatch ? exceptionProxy(tag) : result;
603     }
604 
605     private static Object parseShortArray(int length,
606                                    ByteBuffer buf, ConstantPool constPool) {
607         short[] result = new short[length];
608         boolean typeMismatch = false;
609         int tag = 0;
610 
611         for (int i = 0; i < length; i++) {
612             tag = buf.get();
613             if (tag == 'S') {
614                 int index = buf.getShort() & 0xFFFF;
615                 result[i] = (short) constPool.getIntAt(index);
616             } else {
617                 skipMemberValue(tag, buf);
618                 typeMismatch = true;
619             }
620         }
621         return typeMismatch ? exceptionProxy(tag) : result;
622     }
623 
624     private static Object parseBooleanArray(int length,
625                                      ByteBuffer buf, ConstantPool constPool) {
626         boolean[] result = new boolean[length];
627         boolean typeMismatch = false;
628         int tag = 0;
629 
630         for (int i = 0; i < length; i++) {
631             tag = buf.get();
632             if (tag == 'Z') {
633                 int index = buf.getShort() & 0xFFFF;
634                 result[i] = (constPool.getIntAt(index) != 0);
635             } else {
636                 skipMemberValue(tag, buf);
637                 typeMismatch = true;
638             }
639         }
640         return typeMismatch ? exceptionProxy(tag) : result;
641     }
642 
643     private static Object parseStringArray(int length,
644                                     ByteBuffer buf,  ConstantPool constPool) {
645         String[] result = new String[length];
646         boolean typeMismatch = false;
647         int tag = 0;
648 
649         for (int i = 0; i < length; i++) {
650             tag = buf.get();
651             if (tag == 's') {
652                 int index = buf.getShort() & 0xFFFF;
653                 result[i] = constPool.getUTF8At(index);
654             } else {
655                 skipMemberValue(tag, buf);
656                 typeMismatch = true;
657             }
658         }
659         return typeMismatch ? exceptionProxy(tag) : result;
660     }
661 
662     private static Object parseClassArray(int length,
663                                           ByteBuffer buf,
664                                           ConstantPool constPool,
665                                           Class<?> container) {
666         Object[] result = new Class<?>[length];
667         boolean typeMismatch = false;
668         int tag = 0;
669 
670         for (int i = 0; i < length; i++) {
671             tag = buf.get();
672             if (tag == 'c') {
673                 result[i] = parseClassValue(buf, constPool, container);
674             } else {
675                 skipMemberValue(tag, buf);
676                 typeMismatch = true;
677             }
678         }
679         return typeMismatch ? exceptionProxy(tag) : result;
680     }
681 
682     private static Object parseEnumArray(int length, Class<? extends Enum> enumType,
683                                          ByteBuffer buf,
684                                          ConstantPool constPool,
685                                          Class<?> container) {
686         Object[] result = (Object[]) Array.newInstance(enumType, length);
687         boolean typeMismatch = false;
688         int tag = 0;
689 
690         for (int i = 0; i < length; i++) {
691             tag = buf.get();
692             if (tag == 'e') {
693                 result[i] = parseEnumValue(enumType, buf, constPool, container);
694             } else {
695                 skipMemberValue(tag, buf);
696                 typeMismatch = true;
697             }
698         }
699         return typeMismatch ? exceptionProxy(tag) : result;
700     }
701 
702     private static Object parseAnnotationArray(int length,
703                                                Class<? extends Annotation> annotationType,
704                                                ByteBuffer buf,
705                                                ConstantPool constPool,
706                                                Class<?> container) {
707         Object[] result = (Object[]) Array.newInstance(annotationType, length);
708         boolean typeMismatch = false;
709         int tag = 0;
710 
711         for (int i = 0; i < length; i++) {
712             tag = buf.get();
713             if (tag == '@') {
714                 result[i] = parseAnnotation(buf, constPool, container, true);
715             } else {
716                 skipMemberValue(tag, buf);
717                 typeMismatch = true;
718             }
719         }
720         return typeMismatch ? exceptionProxy(tag) : result;
721     }
722 
723     /**
724      * Return an appropriate exception proxy for a mismatching array
725      * annotation where the erroneous array has the specified tag.
726      */
727     private static ExceptionProxy exceptionProxy(int tag) {
728         return new AnnotationTypeMismatchExceptionProxy(
729             "Array with component tag: " + tag);
730     }
731 
732     /**
733      * Skips the annotation at the current position in the specified
734      * byte buffer.  The cursor of the byte buffer must point to
735      * an "annotation structure" OR two bytes into an annotation
736      * structure (i.e., after the type index).
737      *
738      * @parameter complete true if the byte buffer points to the beginning
739      *     of an annotation structure (rather than two bytes in).
740      */
741     private static void skipAnnotation(ByteBuffer buf, boolean complete) {
742         if (complete)
743             buf.getShort();   // Skip type index
744         int numMembers = buf.getShort() & 0xFFFF;
745         for (int i = 0; i < numMembers; i++) {
746             buf.getShort();   // Skip memberNameIndex
747             skipMemberValue(buf);
748         }
749     }
750 
751     /**
752      * Skips the annotation member value at the current position in the
753      * specified byte buffer.  The cursor of the byte buffer must point to a
754      * "member_value structure."
755      */
756     private static void skipMemberValue(ByteBuffer buf) {
757         int tag = buf.get();
758         skipMemberValue(tag, buf);
759     }
760 
761     /**
762      * Skips the annotation member value at the current position in the
763      * specified byte buffer.  The cursor of the byte buffer must point
764      * immediately after the tag in a "member_value structure."
765      */
766     private static void skipMemberValue(int tag, ByteBuffer buf) {
767         switch(tag) {
768           case 'e': // Enum value
769             buf.getInt();  // (Two shorts, actually.)
770             break;
771           case '@':
772             skipAnnotation(buf, true);
773             break;
774           case '[':
775             skipArray(buf);
776             break;
777           default:
778             // Class, primitive, or String
779             buf.getShort();
780         }
781     }
782 
783     /**
784      * Skips the array value at the current position in the specified byte
785      * buffer.  The cursor of the byte buffer must point to an array value
786      * struct.
787      */
788     private static void skipArray(ByteBuffer buf) {
789         int length = buf.getShort() & 0xFFFF;
790         for (int i = 0; i < length; i++)
791             skipMemberValue(buf);
792     }
793 
794     /*
795      * This method converts the annotation map returned by the parseAnnotations()
796      * method to an array.  It is called by Field.getDeclaredAnnotations(),
797      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
798      * This avoids the reflection classes to load the Annotation class until
799      * it is needed.
800      */
801     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
802     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
803         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
804     }
805 }